﻿// -----------------------------------------------------------------------
// <copyright file="BinaryReaderAsync.cs">
// Copyright (c) 2013 Andrey Veselov. All rights reserved.
// License:  Microsoft Public License (MS-PL)
// Contacts: http://andrey.moveax.com  andrey@moveax.com
// </copyright>
// -----------------------------------------------------------------------

namespace PortableImagingLibrary.AsyncSupport
{
    using System;
    using System.Diagnostics.Contracts;
    using System.IO;
    using System.Text;
    using System.Threading.Tasks;

    internal class BinaryReaderAsync : IDisposable
    {
        private Stream _source;

        public bool EndOfStream
        {
            get { return this._source.Length == this._source.Position; }
        }

        public BinaryReaderAsync(Stream source)
        {
            Contract.Requires(source != null);

            this._source = source;
        }

        public async Task<byte[]> ReadBytesAsync(int count)
        {
            var buffer = new byte[count];
            await this._source.ReadAsync(buffer, 0, count)
                .ConfigureAwait(false);

            return buffer;
        }

        public async Task<int> ReadIntAsync()
        {
            const int count = sizeof(int);

            var buffer = new byte[count];
            await this._source.ReadAsync(buffer, 0, count)
                .ConfigureAwait(false);

            return (buffer[0] << 24) + (buffer[1] << 16) + (buffer[2] << 8) + buffer[3];
        }

        public async Task<uint> ReadUintAsync()
        {
            const int count = sizeof(uint);

            var buffer = new byte[count];
            await this._source.ReadAsync(buffer, 0, count)
                .ConfigureAwait(false);

            return (uint)((buffer[0] << 24) + (buffer[1] << 16) + (buffer[2] << 8) + buffer[3]);
        }

        public async Task<string> ReadStringAsync(int count)
        {
            Contract.Requires(count > 0);
            Contract.Ensures(!string.IsNullOrEmpty(Contract.Result<Task<string>>().Result));

            var buffer = new byte[count];
            await this._source.ReadAsync(buffer, 0, count)
                .ConfigureAwait(false);

            return Encoding.UTF8.GetString(buffer, 0, count);
        }

        #region IDisposable Members

        public void Dispose()
        {
            if (this._source == null)
                return;

            this._source.Dispose();
            this._source = null;
        }

        #endregion IDisposable Members
    }
}
